package com.by.gateway.config;

import com.by.gateway.service.GatewayForwardService;
import com.by.log.Logger;
import com.by.log.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpData;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
import io.netty.util.CharsetUtil;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static final Logger logger = LoggerFactory.getLogger(HttpRequestHandler.class);
    private final ObjectMapper mapper = new ObjectMapper();

    private final GatewayForwardService gatewayForwardService;

    public HttpRequestHandler(GatewayForwardService gatewayForwardService) {
        this.gatewayForwardService = gatewayForwardService;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
        // 由于是异步操作，需要 retain() 来增加引用计数，防止 msg 在处理前被释放
        msg.retain();

        try {
            // 1. 构建请求数据容器
            Map<String, Object> requestData = new HashMap<>();

            // 2. 解析基本信息
            URI uri = new URI(msg.uri());
            requestData.put("$path", uri.getPath());
            requestData.put("$method", msg.method().name());
            requestData.put("$queryString", uri.getQuery());

            // 3. 解析请求头
            Map<String, String> headers = new HashMap<>();
            msg.headers().forEach(entry -> headers.put(entry.getKey(), entry.getValue()));
            requestData.put("$headers", headers);

            // 4. 解析查询参数
            QueryStringDecoder decoder = new QueryStringDecoder(msg.uri());
            Map<String, String> queryParams = new HashMap<>();
            decoder.parameters().forEach((key, values) -> {
                if (!values.isEmpty()) {
                    queryParams.put(key, values.get(0));
                }
            });
            requestData.put("$queryParams", queryParams);

            // 5. 解析请求体和表单/文件数据
            if (msg.method() == HttpMethod.POST || msg.method() == HttpMethod.PUT) {
                String contentType = msg.headers().get(HttpHeaderNames.CONTENT_TYPE);
                if (contentType != null && contentType.startsWith("multipart/form-data")) {
                    // 处理 multipart/form-data
                    HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(msg);
                    Map<String, String> formParams = new HashMap<>();
                    Map<String, byte[]> fileParams = new HashMap<>();

                    List<InterfaceHttpData> bodyParts = postDecoder.getBodyHttpDatas();
                    for (InterfaceHttpData data : bodyParts) {
                        if (data.getHttpDataType() == HttpDataType.FileUpload) {
                            FileUpload fileUpload = (FileUpload) data;
                            // 确保文件内容可读
                            if (fileUpload.isCompleted()) {
                                // 将文件内容转换为字节数组
                                fileParams.put(fileUpload.getName(), fileUpload.get());
                            }
                        } else if (data.getHttpDataType() == HttpDataType.Attribute) {
                            Attribute attribute = (Attribute) data;
                            formParams.put(attribute.getName(), attribute.getValue());
                        }
                    }
                    requestData.put("$formParams", formParams);
                    requestData.put("$fileParams", fileParams);
                    postDecoder.destroy(); // 释放资源
                } else if (msg.content().isReadable()) {
                    // 处理普通请求体（如 JSON）
                    String body = msg.content().toString(CharsetUtil.UTF_8);
                    requestData.put("$body", body);
                }
            }

            // 6. 调用异步方法，并注册回调
            CompletableFuture<Object> future = gatewayForwardService.forward(requestData);

            future.whenComplete((result, throwable) -> {
                FullHttpResponse response;
                if (throwable != null) {
                    logger.error("Failed to forward request asynchronously", throwable);
                    response = createHttpResponse("Internal Server Error: " + throwable.getMessage(), HttpResponseStatus.INTERNAL_SERVER_ERROR);
                } else {
                    response = createHttpResponse(result, OK);
                }

                // 将响应写回到客户端并关闭连接
                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
                // 释放 FullHttpRequest 资源
                msg.release();
            });

        } catch (Exception e) {
            logger.error("Failed to process request", e);
            FullHttpResponse response = createHttpResponse("Internal Server Error: " + e.getMessage(), HttpResponseStatus.INTERNAL_SERVER_ERROR);
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
            msg.release(); // 释放资源
        }
    }

    private FullHttpResponse createHttpResponse(Object content, HttpResponseStatus status) {
        try {
            String jsonContent = mapper.writeValueAsString(content);
            ByteBuf responseBuf = io.netty.buffer.Unpooled.copiedBuffer(jsonContent, CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, responseBuf);
            response.headers().set(CONTENT_TYPE, "application/json; charset=UTF-8");
            response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
            return response;
        } catch (Exception e) {
            logger.error("Failed to create HTTP response", e);
            String errorMsg = "{\"error\":\"Failed to serialize response\"}";
            ByteBuf errorBuf = io.netty.buffer.Unpooled.copiedBuffer(errorMsg, CharsetUtil.UTF_8);
            FullHttpResponse errorResponse = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR, errorBuf);
            errorResponse.headers().set(CONTENT_TYPE, "application/json; charset=UTF-8");
            errorResponse.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, errorResponse.content().readableBytes());
            return errorResponse;
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("Channel exception caught", cause);
        ctx.close();
    }
}